/*
 * Copyright (C) 2008-2010 Josef Hardi <josef.hardi@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

package edu.bth.student.android.photohand.provider;

import edu.bth.student.android.photohand.provider.PhotoHandSchema.Albums;
import edu.bth.student.android.photohand.provider.PhotoHandSchema.Photos;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import java.util.HashMap;

public class PhotoHandContentProvider extends ContentProvider {

  private static final String TAG = "PhotoHandContentProvider";
  private static final String DATABASE_NAME = "photohand.db";
  private static final int DATABASE_VERSION = 8;

  private static final String TABLE_ALBUMS = "Albums";
  private static final String TABLE_PHOTOS = "Photos";

  private static HashMap<String, String> ALBUM_LIST_PROJECTION_MAP;
  private static HashMap<String, String> PHOTO_LIST_PROJECTION_MAP;

  private static final int ALBUMS = 1;
  private static final int ALBUMS_ID = 2;
  private static final int ALBUMS_PHOTOS = 3;
  private static final int ALBUMS_PHOTOS_ID = 4;
  private static final int PHOTOS = 5;
  private static final int PHOTOS_ID = 6;

  private static final UriMatcher URI_MATCHER;

  private DatabaseHelper dbHelper;

  @Override
  public int delete(Uri arg0, String arg1, String[] arg2) {
    // TODO Add delete feature
    return 0;
  }

  @Override
  public String getType(Uri uri) {
    switch (URI_MATCHER.match(uri)) {
    case ALBUMS:
      return Albums.CONTENT_TYPE;

    case ALBUMS_ID:
      return Albums.CONTENT_ITEM_TYPE;

    case ALBUMS_PHOTOS:
    case PHOTOS:
      return Photos.CONTENT_TYPE;

    case ALBUMS_PHOTOS_ID:
    case PHOTOS_ID:
      return Photos.CONTENT_ITEM_TYPE;

    default:
      throw new IllegalArgumentException("Unknown URI " + uri);
    }
  }

  @Override
  public Uri insert(Uri uri, ContentValues initialValues) {
    // Validate the requested URI
    if (URI_MATCHER.match(uri) != ALBUMS
        && URI_MATCHER.match(uri) != ALBUMS_PHOTOS) {
      throw new IllegalArgumentException("Unknown URI " + uri);
    }

    ContentValues values;
    if (initialValues != null) {
      // Creates a set of values copied from the given set
      values = new ContentValues(initialValues);
    } else {
      values = new ContentValues();
    }

    long rowId;
    switch (URI_MATCHER.match(uri)) {
    case ALBUMS:
      rowId = insertAlbum(values);
      if (rowId > 0) {
        Uri albumUri = ContentUris.withAppendedId(uri, rowId);
        getContext().getContentResolver().notifyChange(albumUri, null);
        return albumUri;
      }
      break;

    case ALBUMS_PHOTOS:
      rowId = insertPhoto(values);
      if (rowId > 0) {
        Uri photoUri = ContentUris.withAppendedId(uri, rowId);
        getContext().getContentResolver().notifyChange(photoUri, null);
        return photoUri;
      }
      break;

    default:
      throw new IllegalArgumentException("Unknown URI " + uri);
    }

    throw new SQLException("Failed to insert row into " + uri);
  }

  @Override
  public boolean onCreate() {
    dbHelper = new DatabaseHelper(getContext());
    return true;
  }

  @Override
  public Cursor query(Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

    String defaultSort = null;

    switch (URI_MATCHER.match(uri)) {
    case ALBUMS:
      qb.setTables(TABLE_ALBUMS);
      qb.setProjectionMap(ALBUM_LIST_PROJECTION_MAP);
      defaultSort = Albums.DEFAULT_SORT_ORDER;
      break;

    case ALBUMS_ID:
      qb.setTables(TABLE_ALBUMS);
      qb.appendWhere(Albums._ID + uri.getPathSegments().get(1));
      break;

    case ALBUMS_PHOTOS:
    case PHOTOS:
      qb.setTables(TABLE_PHOTOS);
      qb.setProjectionMap(PHOTO_LIST_PROJECTION_MAP);
      defaultSort = Photos.DEFAULT_SORT_ORDER;
      break;

    case ALBUMS_PHOTOS_ID:
    case PHOTOS_ID:
      qb.setTables(TABLE_PHOTOS);
      qb.appendWhere(Photos._ID + uri.getPathSegments().get(1));
      break;

    default:
      throw new IllegalArgumentException("Unknown URI " + uri);
    }

    // If no sort order is specified use the default
    String orderBy;
    if (TextUtils.isEmpty(sortOrder)) {
      orderBy = defaultSort;
    } else {
      orderBy = sortOrder;
    }

    // Get the database and run the query
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
        orderBy);

    // Tell the cursor what URI to watch, so it knows when its source data
    // changes
    c.setNotificationUri(getContext().getContentResolver(), uri);
    return c;
  }

  @Override
  public int update(Uri uri, ContentValues values, String selection,
      String[] selectionArgs) {
    // TODO Add update feature
    return 0;
  }

  private long insertAlbum(ContentValues values) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    long rowId = db.insert(TABLE_ALBUMS, Albums.TITLE, values);
    return rowId;
  }

  private long insertPhoto(ContentValues values) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    long rowId = db.insert(TABLE_PHOTOS, Photos.TITLE, values);
    return rowId;
  }

  /**
   * This class helps open, create, and upgrade the database file.
   */
  private static class DatabaseHelper extends SQLiteOpenHelper {

    DatabaseHelper(Context context) {
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
      onCreateAlbum(db);
      onCreatePhoto(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      assert (newVersion == DATABASE_VERSION);
      Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
          + newVersion + ", which will destroy all old data.");

      switch (oldVersion) {
      default:
        Log.w(TAG, "Version too old, wiping out database contents.");
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_ALBUMS + ";");
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_PHOTOS + ";");
        onCreate(db);
        break;
      }
    }

    /*
     * Create table Albums
     */
    protected void onCreateAlbum(SQLiteDatabase db) {
      db.execSQL("CREATE TABLE " + TABLE_ALBUMS + " (" + Albums._ID
          + " INTEGER PRIMARY KEY, " + Albums.TITLE + " TEXT, " + Albums.OWNER
          + " TEXT, " + Albums.UPDATED_ON + " TEXT);");
    }

    /*
     * Create table Photos
     */
    protected void onCreatePhoto(SQLiteDatabase db) {
      db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" + Photos._ID
          + " INTEGER PRIMARY KEY, " + Photos.TITLE + " TEXT, "
          + Photos.PUBLISHED_ON + " TEXT, " + Photos.URL + " TEXT);");
    }
  }

  static {
    URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "albums", ALBUMS);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "albums/#", ALBUMS_ID);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "albums/#/photos",
        ALBUMS_PHOTOS);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "albums/#/photos/#",
        ALBUMS_PHOTOS_ID);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "photos", PHOTOS);
    URI_MATCHER.addURI(PhotoHandSchema.AUTHORITY, "photos/#", PHOTOS_ID);

    ALBUM_LIST_PROJECTION_MAP = new HashMap<String, String>();
    ALBUM_LIST_PROJECTION_MAP.put(Albums._ID, Albums._ID);
    ALBUM_LIST_PROJECTION_MAP.put(Albums.TITLE, Albums.TITLE);
    ALBUM_LIST_PROJECTION_MAP.put(Albums.OWNER, Albums.OWNER);
    ALBUM_LIST_PROJECTION_MAP.put(Albums.UPDATED_ON, Albums.UPDATED_ON);

    PHOTO_LIST_PROJECTION_MAP = new HashMap<String, String>();
    PHOTO_LIST_PROJECTION_MAP.put(Photos._ID, Photos._ID);
    PHOTO_LIST_PROJECTION_MAP.put(Photos.TITLE, Photos.TITLE);
    PHOTO_LIST_PROJECTION_MAP.put(Photos.URL, Photos.URL);
    PHOTO_LIST_PROJECTION_MAP.put(Photos.PUBLISHED_ON, Photos.PUBLISHED_ON);
  }
}
